#ifndef	_SIMCORE_H_
#define	_SIMCORE_H_

#pragma ident	"@(#)simcore.h	1.36	06/06/12 SMI"

#ifdef	__cplusplus
extern "C" {
#endif


#include <pthread.h>

typedef struct CONFIG_PROC config_proc_t;
typedef struct CONFIG_DEV config_dev_t;
typedef struct CONFIG_ADDR config_addr_t;
typedef struct PROC_TYPE proc_type_t;
typedef struct DEV_TYPE dev_type_t;
typedef struct DOMAIN domain_t;
typedef struct SYSTEM system_t;
typedef struct ERROR_CONFIG error_conf_t;
typedef struct REG_MAP	reg_map_t;


#include "list.h"

typedef enum MACCESS maccess_t;

	/*
	 * Internal structures for execution data cache simulation
	 */

#include "xdcache.h"



	/*
	 * Op fields for memory access operations
	 *
	 * Note: These field values are used by the core for embedding
	 * in decoded instructions. However, processor modules may also
	 * choose additional specific encodings that are restricted to
	 * those modules only and are defined elsewhere.
	 *
	 * Care should be taken when modifying these codes as not to
	 * tread on value defined elsewhere (values >= 0x100 && < 0xfff0).
	 *
	 * Processor specific modules should use the value
	 * MA_Non_Gen_Base as the base for their specific definitions.
	 *
	 * The generic core values reside in no more than 8 bits
	 * and are used to define basic load, store and cas operations.
	 */

enum MACCESS {
	MA_Size_Mask	= 0xf,

	MA_Size8	= 0x0,
	MA_Size16	= 0x1,
	MA_Size32	= 0x2,
	MA_Size64	= 0x3,
	MA_Size128	= 0x4,

	MA_Op_MaskGeneric = 0xf0,
	MA_Op_Mask	= 0xfff0,

	MA_Ld		= 0x00,
	MA_LdSigned	= 0x10,
	MA_LdDouble	= 0x20,		/* SPARC only ? */
	MA_LdFloat	= 0x30,
	MA_St		= 0x40,
	MA_StFloat	= 0x50,
	MA_CAS		= 0x60,
	MA_StDouble	= 0x70,		/* SPARC only ? */
	MA_LdSt		= 0x80,
	MA_Swap		= 0x90,

	MA_Non_Gen_Base = 0x100,	/* First non generic useable value */
	MA_Non_Gen_Skip = 0x10,		/* skip value for non-generic codes */

	MA_ldu8		= MA_Size8 | MA_Ld,
	MA_ldu16	= MA_Size16 | MA_Ld,
	MA_ldu32	= MA_Size32 | MA_Ld,
	MA_ldu64	= MA_Size64 | MA_Ld,

	MA_lddu64	= MA_Size64 | MA_LdDouble,	/* loads 64 bit value 64 bit aligned */
	MA_stdu64	= MA_Size64 | MA_StDouble,

	MA_lddu128	= MA_Size128 | MA_LdDouble,	/* loads 2x64 bit
							   values atomically
							   128 bit aligned */

	MA_lds8		= MA_Size8 | MA_LdSigned,
	MA_lds16	= MA_Size16 | MA_LdSigned,
	MA_lds32	= MA_Size32 | MA_LdSigned,
	MA_lds64	= MA_Size64 | MA_LdSigned,

	MA_st8		= MA_Size8 | MA_St,
	MA_st16		= MA_Size16 | MA_St,
	MA_st32		= MA_Size32 | MA_St,
	MA_st64		= MA_Size64 | MA_St,

	MA_ldfp32	= MA_Size32 | MA_LdFloat,
	MA_ldfp64	= MA_Size64 | MA_LdFloat,
	MA_ldfp128	= MA_Size128 | MA_LdFloat,

	MA_stfp32	= MA_Size32 | MA_StFloat,
	MA_stfp64	= MA_Size64 | MA_StFloat,
	MA_stfp128	= MA_Size128 | MA_StFloat,

	MA_cas32	= MA_Size32 | MA_CAS,
	MA_cas64	= MA_Size64 | MA_CAS,

	MA_ldstub	= MA_Size8 | MA_LdSt,
	MA_swap		= MA_Size32 | MA_Swap
};



	/*
	 * Data structures passed as pointers, but private to the
	 * simulator core.
	 */

typedef void *(*instn_exec_t)();


typedef struct XICACHE_INSTN xicache_instn_t;
typedef struct XICACHE_LINE xicache_line_t;
typedef struct XICACHE xicache_t;
typedef union DECODED_INSTN decoded_instn_t;
typedef struct BP_INFO bp_info_t;
typedef struct BREAKPOINT breakpoint_t;


typedef LIST_DEF( simcpu_list_t, simcpu_t );

extern simcpu_list_t simcpu_list;





	/*
	 * Simulator core CPU structure ..
	 * defines NINT integer registers, NFP floating point
	 * registers etc ...
	 */

#define	NINT	32
#define NFP_128 16
#define NFP_64  32
#define NFP_32  64


/*
typedef struct ERROR {
	void *		itep;		// track itlb entry with error until demapped 
	void *		dtep;		// track dtlb entry with error until demapped 
	uint8_t		tlb_idx[4];	// tlb entry with parity error 
#define	IMDU_IDX	0
#define	IMTU_IDX	1
#define	DMDU_IDX	2
#define	DMTU_IDX	3
	uint64_t	l2_write;	// write to l2 on partial store or atomic hit //
	uint64_t	partial_st;	// partial store l2 access 
	uint8_t		reg;		// register number with ECC error 
	tvaddr_t	addr;		// pa or va in error 
	bool_t		check_xicache;	// check error conditions on xdcache access 
	bool_t		check_dtlb;	// check error conditions on dtlb access 
	bool_t		check_xdcache;	// check error conditions on xdcache access 
        error_conf_t *	errlistp;	// errors to post for this simcpu 
} error_t;

#define	STATE_DISABLED	0x1LL
#define	STATE_PARKED	0x2LL

#if ERROR_TRAP_GEN // { 
//
 // Error Trap Gen Stuff
 //

typedef enum {
	ERROR_ON_LOAD,
	ERROR_ON_STORE,
	ERROR_ON_LOAD_OR_STORE
} ee_access_t;

typedef enum {
	EE_PARSED,	// user input has been completely parsed 
	EE_ASSIGNED,	// assigned to an sp (watching for trigger) 
	EE_TRIGGERED	// error event trigger conditions met 
} ee_status_t;

#define	ERROR_TL_NONE		0xffffffff
#define	ERROR_INSTN_CNT_NONE	UINT64_MAX

typedef union {
	uint64_t	all;	// used to test/clear all options 
	struct {
		uint64_t opts_pad:54;
		uint64_t trigger_cnt:1;
		uint64_t tl:1;
		uint64_t priv:1;
		uint64_t access:1;
		uint64_t address:1;
		uint64_t pc:1;
		uint64_t instn_cnt:1;
		uint64_t target_cpuid:1;
		uint64_t error_str:1;
		uint64_t trap_num:1;
	} bits;
} error_event_options_t;

typedef struct error_event {
	uint64_t	trap_num;
	char          	*error_str;
	int64_t    	target_cpuid;
	int64_t      	instn_cnt;
	int64_t      	pc;
	struct {
		ee_access_t	access;
		uint64_t	addr;
	} address;
	int 			priv;
	int 			tl;
	ee_status_t		ee_status;
	int			trigger_cnt;
	error_event_options_t	options;
	struct error_asi 	*temp_error_asi_list_rootp;
	struct error_event 	*nextp;
} error_event_t;

typedef struct error_asi {
	int		asi;
	uint64_t	va; // 0x1 means all VAs 
	uint64_t	nand_mask; // applied to register before or_mask 
	uint64_t	or_mask;
	int		access_cnt;
	uint64_t	asi_reg;
	struct error_asi *nextp;
} error_asi_t;
#endif // ERROR_TRAP_GEN } 
*/

struct SIMCPU {
	uint64_t	intreg[NINT];	/* Register file info always first elements ! */
        union {
                ieee_fp32_t     s32[NFP_32];
                ieee_fp64_t     s64[NFP_64];
                ieee_fp128_t    s128[NFP_128];          /* largest FP type to ensure correct alignment */
        } fpreg;

	tvaddr_t	pc;		/* Program counter */
	tvaddr_t	npc;		/* Next PC if used by target */

	uint64_t	miscreg[8];	/* misc 64 bit registers - target dependent usage */
					/* for target=sparcv9: */
					/* misc[0] = CCR */

	uint64_t	scratch64;	/* emergency scratch */


	bool_t		attention;	/* true if some simulator exception to consider */
					/* see below */

#if ERROR_INJECTION
	error_t *	errorp;		/* pointer to flags and stashed error values */
	bool_t		error_enabled;	/* cycle match happened and errors to post */
	bool_t		error_check;	/* first-level flag to check error conditions */
	uint8_t		error_priv;	/* privilege level to post error */
#endif

	uint64_t	state_bits;	/* collection of state bits */
	int		runnable;	/* determined from the above */

	exec_thread_t *	etp;		/* pointer to exec_thread that this scheduler list is on */
	simcpu_t *	headp;		/* pointer to the head simcpu of the scheduler list */
	simcpu_t *	nextp;		/* next in scheduler list */

	xicache_t *	xicachep;	/* pointer to local execution cache */

					/* cpu specific handler for an xicache miss */
	void		(*xic_miss)(simcpu_t *, xicache_line_t *, tvaddr_t addr);

	config_addr_t *	xic_miss_addrp;	/* cpu specific cache of address used to */
					/* satisfy last XC miss - only used by sp->xic_miss */

	int		gid;		/* global simcpu id */

		/* How this simulator cpu corresponds to the
		 * specific CPU defined.
		 */
	config_proc_t * config_procp;
	void *		specificp;		/* target specific data pointer */
	void		(*decodemep)(simcpu_t *, xicache_instn_t *);		/* decodeme function for this cpu */
	void *		decodemedatap;		/* decodeme data for this cpu */

#if OLDPIC /* { */
		/*
		 * per CPU performance counters
		 */
	uint32_t	pic0;
	uint32_t	pic1;
	uint64_t	pcr;
	uint64_t	pic_target;
	uint64_t	pic_cycle;	/* val of cycle the last time we updated pic */
#endif	/* OLDPIC } */
	
#if ERROR_TRAP_GEN /* { */
	simcycle_t	error_cycle;
	bool_t		error_pending;
	bool_t		error_cycle_reached;
	error_event_t	*eep;
#endif /* ERROR_TRAP_GEN } */

	simcycle_t	cycle;
	void		(*cycle_target_match)(simcpu_t * sp);
	uint64_t	cycle_target;
	simcycle_t	total_instr;
	uint64_t	quantum_target;

#if PERFORMANCE_CHECK /* { */
#define	PERF_CYCLE_GAP	10000000 /* figure time for every 1M instructions */
	hrtime_t	last_hrtime;
	hrtime_t	total_hrtime;
	simcycle_t	prev_target;
	simcycle_t	perf_target;
	uint64_t	prev_icount;
	uint64_t	xdc_hits, xdc_misses;
	uint64_t	prev_xdc_hits, prev_xdc_misses;
	uint64_t	xic_hits, xic_misses;
	uint64_t	prev_xic_hits, prev_xic_misses;
#endif /* } */



#if ENABLE_MAGIC_TRAPS	/* { */
		/* This for the magic trap that enables us to count instructions */
	simcycle_t	magic_count;
#endif			/* } */
		/*
		 * Different reasons why we should be paying attention
		 */

	bool_t		sync_pending;
	bool_t		async_event;	/* set if another entity changed simcpu_t state */
	bool_t		exception_pending;

		/*
		 * additional cache structures
		 */

	bp_info_t *	bp_infop;

	xdcache_t	xdc;

#if DEBUG_HOOK /* { */
	void		*debug;
#endif /* } DEBUG_HOOK */

	proc_debug_t	*proc_debugp;
};



#ifndef	NDEBUG 
#define	DBG_EXEC_LOOP	0x100000000LL
#define	DBGEXECLOOP(s)	do { if (debug_bits & DBG_EXEC_LOOP) { s } } while (0)	/* debug exec_loop */
#else
#define	DBGEXECLOOP(s)	do { } while (0)	/* debug exec_loop */
#endif

#define	EXEC_QUANTUM	8192

#define	set_attention(_sp)	do { (_sp)->attention = true; } while (0)


extern simcpu_t * sim_cpu_alloc(
		config_proc_t * cfp,
		void * specificp);

extern void simcore_start(void);
extern void simcore_stop(void);
extern void simcore_cpu_enable(simcpu_t *sp);
extern void simcore_cpu_disable(simcpu_t *sp);
extern void simcore_cpu_state_park(simcpu_t *sp);
extern void simcore_cpu_state_unpark(simcpu_t *sp);

struct EXEC_THREAD {
	int		id;		/* Id for the exec_thread */
	simcpu_t *	allp;		/* pointer to all cpus assigned */

	int		nsimcpus;	/* number of simcpus assigned to this thread */
};

	/* to get the number of instructions executed by simcpu_t */
#define	ICOUNT(_sp)	((_sp)->total_instr + ((_sp)->cycle % (EXEC_QUANTUM)))

extern void	cycle_target_off(simcpu_t *sp);

#if !defined(NDEBUG)    /* { */
void simcore_update_debug_bits(uint64_t newval);
#endif          /* } */


#ifdef	__cplusplus
}
#endif

#endif	/* _SIMCORE_H_ */
